/**
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.googlecode.crawlerextractor.crawler4j.url;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
import javax.persistence.Version;

import org.hibernate.annotations.Index;

import com.googlecode.crawlerextractor.common.PersistentObject;
import com.googlecode.crawlerextractor.crawler4j.url.utils.TLDList;

/**
 * @author Yasser Ganjisaffar <lastname at gmail dot com>
 */

@Entity
@Table(name="crawler_weburl")
@NamedQueries(value = {
		@NamedQuery(name = "find.NextURL", query = "SELECT w FROM WebURL as w WHERE w.status ='QUEUED' ORDER BY w.priority,w.depth"),
		@NamedQuery(name = "find.UpdateProcessing2Queued", query = "UPDATE  WebURL as w SET w.status='QUEUED' WHERE w.status ='PROCESSING'"),
		@NamedQuery(name = "count.Queued", query = "SELECT COUNT(w) from  WebURL as w WHERE w.status ='QUEUED'"),
		@NamedQuery(name = "count.Processing", query = "SELECT COUNT(w) from  WebURL as w WHERE w.status ='QUEUED'") })
public class WebURL extends PersistentObject  {

	private static final long serialVersionUID = 1L;
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	private Integer id;
	@Version
	private Integer version;


	@Column(updatable=false,nullable=false)
	private String url;

	@Enumerated(EnumType.STRING)
	@Column(nullable=false)
	@Index(name="IDX_STATUS")
	private WebUrlStatus status = WebUrlStatus.QUEUED;

	@Column(updatable=false,nullable=false)
	private int docid;
	@Column(updatable=false)
	private int parentDocid;
	@Column(updatable=false)
	private String parentUrl;
	@Column(updatable=false,nullable=false)
	private short depth;
	@Column(updatable=false,nullable=false)
	private String domain;
	@Column(updatable=false,nullable=false)
	private String subDomain;
	@Column(updatable=false,nullable=false)
	private String path;
	@Column()
	private String anchor;
	@Column(updatable=false,nullable=false)
	private byte priority = 100;

	public WebURL() {
		super();

	}
	public WebURL(final String url) {
		super();
		this.url = url;
	}

	@Override
	public boolean equals(final Object o) {
		if (this == o) {
			return true;
		}
		if (o == null || this.getClass() != o.getClass()) {
			return false;
		}

		final WebURL otherUrl = (WebURL) o;
		return url != null && url.equals(otherUrl.getURL());

	}

	/**
	 * Returns the anchor string. For example, in <a href="example.com">A sample
	 * anchor</a> the anchor string is 'A sample anchor'
	 */
	public String getAnchor() {
		return anchor;
	}


	/**
	 * Returns the crawl depth at which this Url is first observed. Seed Urls
	 * are at depth 0. Urls that are extracted from seed Urls are at depth 1,
	 * etc.
	 */
	public short getDepth() {
		return depth;
	}

	/**
	 * Returns the unique document id assigned to this Url.
	 */
	public int getDocid() {
		return docid;
	}

	/**
	 * Returns the domain of this Url. For 'http://www.example.com/sample.htm',
	 * domain will be 'example.com'
	 */
	public String getDomain() {
		return domain;
	}

	/**
	 * Get the id.
	 * 
	 * @return the id.
	 */

	public Integer getId() {
		return id;
	}

	/**
	 * Returns the unique document id of the parent page. The parent page is the
	 * page in which the Url of this page is first observed.
	 */
	public int getParentDocid() {
		return parentDocid;
	}

	/**
	 * Returns the url of the parent page. The parent page is the page in which
	 * the Url of this page is first observed.
	 */
	public String getParentUrl() {
		return parentUrl;
	}

	/**
	 * Returns the path of this Url. For 'http://www.example.com/sample.htm',
	 * domain will be 'sample.htm'
	 */
	public String getPath() {
		return path;
	}

	/**
	 * Returns the priority for crawling this URL. A lower number results in
	 * higher priority.
	 */
	public byte getPriority() {
		return priority;
	}

	/**
	 * Get the status.
	 * 
	 * @return the status.
	 */
	public WebUrlStatus getStatus() {
		return status;
	}

	public String getSubDomain() {
		return subDomain;
	}

	/**
	 * Get the url.
	 * 
	 * @return the url.
	 */
	public String getUrl() {
		return url;
	}

	/**
	 * Returns the Url string
	 */
	public String getURL() {
		return url;
	}

	/**
	 * Get the version.
	 * 
	 * @return the version.
	 */
	public Integer getVersion() {
		return version;
	}

	public void setAnchor(final String anchor) {
		this.anchor = anchor;
	}


	public void setDepth(final short depth) {
		this.depth = depth;
	}

	public void setDocid(final int docid) {
		this.docid = docid;
	}

	/**
	 * Set the domain.
	 * 
	 * @param domain
	 *            The domain to set.
	 */
	public void setDomain(final String domain) {
		this.domain = domain;
	}

	/**
	 * Set the id.
	 * 
	 * @param id
	 *            The id to set.
	 */

	public void setId(final Integer id) {
		this.id = id;
	}

	public void setParentDocid(final int parentDocid) {
		this.parentDocid = parentDocid;
	}

	public void setParentUrl(final String parentUrl) {
		this.parentUrl = parentUrl;
	}

	public void setPath(final String path) {
		this.path = path;
	}

	public void setPriority(final byte priority) {
		this.priority = priority;
	}

	/**
	 * Set the status.
	 * 
	 * @param status
	 *            The status to set.
	 */
	public void setStatus(final WebUrlStatus status) {
		this.status = status;
	}

	/**
	 * Set the subDomain.
	 * 
	 * @param subDomain
	 *            The subDomain to set.
	 */
	public void setSubDomain(final String subDomain) {
		this.subDomain = subDomain;
	}

	/**
	 * Set the url.
	 * 
	 * @param url
	 *            The url to set.
	 */
	public void setUrl(final String url) {
		this.url = url;
	}

	public void setURL(final String url) {
		this.url = url;

		final int domainStartIdx = url.indexOf("//") + 2;
		final int domainEndIdx = url.indexOf('/', domainStartIdx);
		domain = url.substring(domainStartIdx, domainEndIdx);
		subDomain = "";
		final String[] parts = domain.split("\\.");
		if (parts.length > 2) {
			domain = parts[parts.length - 2] + "." + parts[parts.length - 1];
			int limit = 2;
			if (TLDList.contains(domain)) {
				domain = parts[parts.length - 3] + "." + domain;
				limit = 3;
			}
			for (int i = 0; i < parts.length - limit; i++) {
				if (subDomain.length() > 0) {
					subDomain += ".";
				}
				subDomain += parts[i];
			}
		}
		path = url.substring(domainEndIdx);
		final int pathEndIdx = path.indexOf('?');
		if (pathEndIdx >= 0) {
			path = path.substring(0, pathEndIdx);
		}
	}

	/**
	 * Set the version.
	 * 
	 * @param version
	 *            The version to set.
	 */
	public void setVersion(final Integer version) {
		this.version = version;
	}

	@Override
	public String toString() {
		return url;
	}

}
